package com.eco
{
	import com.eco.*;
	import com.framework.*;
	
	import flash.display.MovieClip;
	import flash.display.SimpleButton;
	import flash.events.*;
	import flash.ui.Mouse;
	import flash.utils.*;
		
	//关卡管理器，负责关卡内游戏的初始化、全程控制管理与结束操作
	public class GameStage extends MovieClip
	{
		private var MyFighter:Fighter;//卫士类实例
		
		private var MyEnemyManager:EnemyManager;//敌人管理器
		private var vecEnemy:Vector.<Enemy>;//储存敌人类实例的数组，简化代码
		private var MyEnemy:Enemy;//敌人实例引用
		private var MyEnemy2:Enemy;//敌人实例引用
		private var MyEnemy3:Enemy;//敌人实例引用
		private var iEnemyNum:int;//敌人个数，简化代码
		
		private var MyBonusManager:BonusManager;//道具管理器
		private var vecBonus:Vector.<Bonus>;//储存道具类实例的数组，简化代码
		private var MyBonus:Bonus;//道具实例引用
		private var iBonusNum:int;//道具个数，简化代码
		
		private var w:int;//记录初始舞台长宽
		private var h:int;
		private var bg_w:int;
		private var bg_h:int;
		
		public var iState:int;//关卡的状态
		
		static public var STAGE_RUNNING:int = 0;
		static public var STAGE_PAUSE:int = 1;
		static public var STAGE_WIN:int = 2;
		static public var STAGE_LOSE:int = 3;
		static public var STAGE_DRAW:int = 4;
		
		private var xmlData:XML;
		private var iStage_num_Rec:Number ;      //场景号
		private var iLevel_num_Rec:Number ;		//关卡号
		private var iTotalEnemyNum:int;//本关敌人的总数
		private var iKilledEnemyNum:int;//已经杀死的敌人的数量
		
		//test bg
		private var bg:MovieClip;
		
		//这两要放一个树桩的MC，这个MC是用来判断敌人和卫士出没出树桩的
		private var mcBattleField:MovieClip;
		
		public function GameStage( scene:int, level:int, xmld:XML)
		{			
			//Mouse.hide();
			//卫士
			MyFighter = new Fighter(10,30,10,1,6,1.5);
			if( scene == 3 )
			{
				MyFighter.x = 515;
				MyFighter.y = 260;
			}
			else
			{
				MyFighter.x = 200;
				MyFighter.y = 200;
			}
			addChild(MyFighter);
			
			
			
			//敌人
			MyEnemyManager = new EnemyManager();
			MyEnemyManager.SetFighter(MyFighter);
			addChild(MyEnemyManager);
			vecEnemy = MyEnemyManager.GetEnemyVector();
			iEnemyNum = vecEnemy.length;
			
			//道具
			MyBonusManager = new BonusManager();
			MyBonusManager.SetFighter(MyFighter);
			MyBonusManager.SetEnemyVector(vecEnemy);
			addChild(MyBonusManager);
			vecBonus = MyBonusManager.GetBonusVector();
			iBonusNum = vecBonus.length;
			
			xmlData = xmld;
			iStage_num_Rec = scene;
			iLevel_num_Rec = level;
			OutputXml();//载入这一关的信息
			iKilledEnemyNum = 0;
			CreateBGAndField();//根据载入的信息生成背景和平台
			
			iState = STAGE_RUNNING;
				
			//添加更新函数的触发事件侦听
			this.addEventListener(Event.ENTER_FRAME, Update);
			this.addEventListener(Event.ADDED_TO_STAGE, Initiate);
		
		}
		
		private function Initiate(e:Event):void
		{
			w = stage.width;
			h = stage.height;
			//加背景音派发
		//	dispatchEvent(new CustomEventSound(CustomEventSound.PLAY_SOUND,SoundInfo.BGM_MAINMENU,true,999,0,1));
			this.removeEventListener(Event.ADDED_TO_STAGE, Initiate);
			
			
			CreateSoundEvent( CustomEventSound.PLAY_SOUND, SoundInfo.EFF_STAGE_START);
			CreateSoundEvent( CustomEventSound.STOP_SOUND, SoundInfo.BGM_MAINMENU, true);
			if( iStage_num_Rec == 1 )
				CreateSoundEvent( CustomEventSound.PLAY_SOUND, SoundInfo.BGM_STAGE_RUNNING_S1, true);
			else if( iStage_num_Rec == 2 )
				CreateSoundEvent( CustomEventSound.PLAY_SOUND, SoundInfo.BGM_STAGE_RUNNING_S2, true);
			else if( iStage_num_Rec == 3 )
				CreateSoundEvent( CustomEventSound.PLAY_SOUND, SoundInfo.BGM_STAGE_RUNNING_S3, true);
		}
		
		protected function CreateSoundEvent(type:String, name:String, issoundtrack:Boolean = false, loop:int = 0 ):void
		{
			var evt:CustomEventSound = new CustomEventSound( type, name, issoundtrack,loop );
			dispatchEvent(evt);
		}
		
		
		private function CreateBGAndField():void
		{
			//iStage_num_Rec = 2;
			switch (iStage_num_Rec)	
			{
				case 1:
				{
					bg = new resSceneOneBG();
					mcBattleField = new resSceneOneField();
					break;
				}
				case 2:
				{
					bg = new resSceneTwoBG();
					mcBattleField = new resSceneTwoField();
					break;	
				}
				case 3:
				{
					bg = new resSceneThreeBG();
					mcBattleField = new resSceneThreeField();
					this.x = -275;
					this.y = -200;
					break;	
				}
			}
			bg_w = bg.width;
			bg_h = bg.height;
			this.addChildAt( bg , 0 );
			mcBattleField.visible = false;
			this.addChildAt( mcBattleField, 0 );
		}
		
		private function CollisionFighterEnemy():void
		{
			
			var i:int = 0;
			for(i=0; i<iEnemyNum; i++)
			{
				MyEnemy = vecEnemy[i];
				if( TestCollision(MyEnemy,MyFighter) )
				{
					//如果发生碰撞，检测当前敌人是否处于免疫期
					if(  MyEnemy.bConflicting && MyEnemy.bCollidable )
					{
						//如果可以发生碰撞，则进行一系列操作
						CreateSoundEvent( CustomEventSound.PLAY_SOUND, SoundInfo.EFF_STAGE_COLLISION);
						
						RigidBallCollision(MyEnemy,MyFighter);//刚体小球非对心碰撞物理模拟
						UpdateStateEnemyFighter(MyEnemy);//调用状态更新函数，根据碰撞结果设置敌人与卫士的新状态
						MyEnemy.bConflicting = false;//设置当前敌人进入免疫期
					}
				}
				else
				{
					MyEnemy.bConflicting = true;
				}
			}
		}
		
		private function CollisionEnemyEnemy():void
		{
			var i:int = 0;
			var j:int = 0;
			for(i=0; i<iEnemyNum; i++)
			{
				MyEnemy = vecEnemy[i];
				for( j=i+1; j<iEnemyNum; j++ )
				{
					MyEnemy2 = vecEnemy[j];
					if( TestCollision(MyEnemy,MyEnemy2) )
					{
						//如果发生碰撞，检测当前敌人是否处于免疫期
						if(  MyEnemy.bConflicting && MyEnemy2.bConflicting )
						{
							//如果可以发生碰撞，则进行一系列操作
							CreateSoundEvent( CustomEventSound.PLAY_SOUND, SoundInfo.EFF_STAGE_COLLISION);
						
							RigidBallCollision(MyEnemy,MyEnemy2);//刚体小球非对心碰撞物理模拟
							//MyEnemy.bConflicting = false;//设置当前敌人进入免疫期
						}
					}
					else
					{
						MyEnemy.bConflicting = true;
					}
				}
			}
		}
		
		private function CollisionFighterBonus():void
		{
			var i:int = 0;
			for(i=0; i<iBonusNum; i++)
			{
				MyBonus = vecBonus[i];
				if( TestCollision(MyBonus,MyFighter) )
				{
					if( MyBonus.iState == Bonus.STATE_IDLE )
					{
						//已经触发的道具虽然已经设置为不可见，但是并不一定被移除，因此仍有可能被碰撞检测到
						//而已经触发的道具的状态一定不可能是闲置的
						//所以，只有处于闲置状态的道具才是可以触发的
						MyBonus.StartFunction();
					}
				}
			}
		}
		
		private function TestCollision(ballA:RigidBall, ballB:RigidBall):Boolean
		{
			//只检测两球位置是否满足碰撞条件，不考虑其bConflicting标记是否为真
			return ( 
				Math.sqrt( 
				(ballA.x - ballB.x)*(ballA.x - ballB.x) 
				+ 
				(ballA.y - ballB.y)*(ballA.y - ballB.y) 
				) 
				<=
				( ballA.nRadius + ballB.nRadius) 
				);
		}
		private function RigidBallCollision( ballA:RigidBall, ballB:RigidBall ):void
		{
			//刚体小球非对心碰撞，动量守恒能量守恒，不考虑小球之间摩擦与旋转
			//第一步，获取对两球速度向量的引用
			var spdA:MyVector2D = ballA.v2dSpeed;
			var spdB:MyVector2D = ballB.v2dSpeed;
			
			//第二步，获取两球球心连线方向与垂直方向的向量
			var dis:MyVector2D = new MyVector2D( ballA.x - ballB.x, ballA.y - ballB.y);//球心连线方向向量
			var disNom:MyVector2D = dis.getNormal();//球心连线垂直方向向量
			
			//第三步，分别获取球A球B在第二步中两个方向上的投影向量
			var spdAdis:MyVector2D = dis.scaleNew( dis.dot(spdA)/( dis.getLength()*dis.getLength() ) );
			var spdAdisNom:MyVector2D = disNom.scaleNew( disNom.dot(spdA)/( disNom.getLength()*disNom.getLength() ) );
			var spdBdis:MyVector2D = dis.scaleNew( dis.dot(spdB)/( dis.getLength()*dis.getLength() ) );
			var spdBdisNom:MyVector2D = disNom.scaleNew( disNom.dot(spdB)/( disNom.getLength()*disNom.getLength() ) );
			
			//第四步，在平心球心连线方向做动量定理求得新速度，垂直球心连线方向速度不变
			var spdAdiscur:MyVector2D = GetVelocity(ballA.iMass,ballB.iMass,spdAdis,spdBdis);
			var spdBdiscur:MyVector2D = GetVelocity(ballB.iMass,ballA.iMass,spdBdis,spdAdis);
			
			//第五步，将球A的速度合成，将球B的速度合成，更新两球速度向量
			spdA.x = spdAdiscur.x + spdAdisNom.x;
			spdA.y = spdAdiscur.y + spdAdisNom.y;
			spdB.x = spdBdiscur.x + spdBdisNom.x;
			spdB.y = spdBdiscur.y + spdBdisNom.y;
		}
		
		private function GetVelocity(ma:Number, mb:Number, va:MyVector2D, vb:MyVector2D):MyVector2D
		{
			//给定两物体速度向量与质量，由动量守恒与能量守恒得到第一个物体（ma,va）的结果速度向量
			var vx:Number = ( 2*mb*vb.x + ma*va.x - mb*va.x )/(ma + mb);
			var vy:Number = ( 2*mb*vb.y + ma*va.y - mb*va.y )/(ma + mb);
			return new MyVector2D( vx, vy );
		}
		
		private function UpdateStateEnemyFighter(enemy:Enemy):void
		{
			//敌人与卫士状态的更新，在碰撞之后调用，以面向过程的方式，强制改变敌人与卫士的状态标志
			
			switch( enemy.iState )
			{
				case Enemy.STATE_IDLE://					敌人闲置
				{
					switch( MyFighter.iState )
					{
						case Fighter.STATE_WIND_START://		旋风
						{
							//卫士赢
							enemy.SetState( Enemy.COLLISION_LOSE );
							break;
						}
						case Fighter.STATE_READY://				闲置
						{
							//卫士赢
							enemy.SetState( Enemy.COLLISION_LOSE );
							break;
						}
						case Fighter.STATE_WIND_CD://			冷却
						{
							//敌人赢
							enemy.SetState( Enemy.COLLISION_WIN );
							break;
						}
						case Fighter.STATE_FREEZED://			硬直
						{
							//敌人赢
							enemy.SetState( Enemy.COLLISION_WIN );
							break;
						}
					}
					break;
				}
				case Enemy.STATE_ATTACK://				敌人攻击
				{
					switch( MyFighter.iState )
					{
						case Fighter.STATE_WIND_START://		旋风
						{
							//卫士赢
							enemy.SetState( Enemy.COLLISION_LOSE );
							break;
						}
						case Fighter.STATE_READY://				闲置
						{
							//敌人赢
							enemy.SetState( Enemy.COLLISION_WIN );
							break;
						}
						case Fighter.STATE_WIND_CD://			冷却
						{
							//敌人赢
							enemy.SetState( Enemy.COLLISION_WIN );
							break;
						}
						case Fighter.STATE_FREEZED://			硬直
						{
							//敌人赢
							enemy.SetState( Enemy.COLLISION_WIN );
							break;
						}
					}
					break;
				}
			}
		}
		
		private function UpdateEnemy():void
		{
			iEnemyNum = vecEnemy.length;
		}
		
		private function UpdateBonus():void
		{
			iBonusNum = vecBonus.length;
		}
		
		/*private function RollScreen():void
		{
			
			var dx:int = stage.mouseX - 275;
			var dy:int = stage.mouseY - 200;
			
			//if( (dx*dx + dy*dy) >= 100*100 )
			//{
				this.x -= dx/100;
				
				this.y -= dy/100;
			//}
			if( this.x >= 0 )
				this.x = 0;
			if( this.x <= (550-bg_w) )
				this.x = 550-bg_w;
			if( this.y >= 0 )
				this.y = 0;
			if( this.y <= (400-bg_h) )
				this.y = 400-bg_h;
		}*/
		
		private function RollScreen():void
		{
			this.x -= MyFighter.v2dSpeed.x;
			this.y -= MyFighter.v2dSpeed.y;
			
			if( this.x >= 0 )
				this.x = 0;
			if( this.x <= (550-bg_w) )
				this.x = 550-bg_w;
			if( this.y >= 0 )
				this.y = 0;
			if( this.y <= (400-bg_h) )
				this.y = 400-bg_h;
		}
		
		private function BonusWrongPositionDetection():void
		{
			//由于道具的生成是全场随机的，因此需要一个错误位置检测函数将形成在平台之外的道具清除
			var i:int = 0;
			for(i=0;i<iBonusNum;i++)
			{
				if( mcBattleField.hitTestPoint(vecBonus[i].x, vecBonus[i].y, true) == false )
				{
					if( vecBonus[i].iState == Bonus.STATE_IDLE )
					{
						vecBonus[i].visible = false;
						vecBonus[i].iState = Bonus.STATE_END;
					}
				}
				else
				{
					if( vecBonus[i].iState == Bonus.STATE_IDLE )
					{
						vecBonus[i].visible = true;
					}
				}
			}
		}
		
		private function GameResultControl():void
		{
			//游戏胜利失败控制类，负责敌人与卫士的出界检测
			var i:int = 0;
			for(i=0;i<iEnemyNum;i++)
			{
				if( mcBattleField.hitTestPoint(vecEnemy[i].x + this.x, vecEnemy[i].y + this.y , true) == false )
				{
					if( vecEnemy[i].iState != Enemy.STATE_END && vecEnemy[i].iState != Enemy.STATE_DEAD )
					{
						if(vecEnemy[i].iType != Enemy.ENEMY_SPEAR)
						{	
							//只有没有死亡的敌人才能判定死亡，避免重复判定
							vecEnemy[i].SetState( Enemy.STATE_DEAD );
							iKilledEnemyNum++;//被杀的敌人数量+1
						}
					}
				}
			}
			
			GameDataController.getInstance().killedEnemies = iKilledEnemyNum;//更新单例里的已经清除的敌人的数量
			
			if( iKilledEnemyNum == iTotalEnemyNum )
			{
			//	trace("win");
				if(iState != STAGE_WIN)
				{
					CreateSoundEvent( CustomEventSound.PLAY_SOUND, SoundInfo.EFF_STAGE_WIN);
					dispatchEvent(new CustomEventResult(CustomEventResult.LEVEL_WIN));
					iState = STAGE_WIN;
				}
			}
			
			if( mcBattleField.hitTestPoint(MyFighter.x + this.x, MyFighter.y + this.y, true) == false )
			{
				trace("lose");
				MyFighter.Dead();
				if(iState != STAGE_LOSE)
				{
					CreateSoundEvent( CustomEventSound.PLAY_SOUND, SoundInfo.EFF_STAGE_LOSE);
					dispatchEvent(new CustomEventResult(CustomEventResult.LEVEL_LOSE));
					iState = STAGE_LOSE;
				}
			}
			else if( MyFighter.iState == Fighter.STATE_DEAD )
			{
				if(iState != STAGE_LOSE)
				{
					CreateSoundEvent( CustomEventSound.PLAY_SOUND, SoundInfo.EFF_STAGE_LOSE);
					dispatchEvent(new CustomEventResult(CustomEventResult.LEVEL_LOSE));
					iState = STAGE_LOSE
				}
			}
		}
			
		public function OutputXml():void 
		{
			var iStage_num:int = iStage_num_Rec;
			var iLevel_num:int = iLevel_num_Rec;
			
			var iEnemy_All_Length:int = xmlData.my_stage.(@id == iStage_num).my_level.(@id == iLevel_num).enemy.length();
			var iEnemy_Length:int = iEnemy_All_Length-xmlData.my_stage.(@id == iStage_num).my_level.(@id == iLevel_num).enemy.(@enemy_type == 5).length();
			var iProperty_Length:int = xmlData.my_stage.(@id == iStage_num).my_level.(@id == iLevel_num).property.length();
			
			var iEnemy_appear_time:int;
			var iEnemy_enemy_type:int;
			var iEnemy_position_x:int;
			var iEnemy_position_y:int;
			
			var iProperty_appear_time:int;
			var iProperty_type:uint;
			var iProperty_type_String:String;
			var iProperty_type_String_length:int;
			
			var arrProperty:Array = new Array();
			var arrProperty_num:int;
			
			for(var i:Number = 0;i<iEnemy_All_Length;i++)
			{
				iEnemy_appear_time = xmlData.my_stage.(@id == iStage_num).my_level.(@id == iLevel_num).enemy[i].@appear_time;
				iEnemy_enemy_type =  xmlData.my_stage.(@id == iStage_num).my_level.(@id == iLevel_num).enemy[i].@enemy_type;
				iEnemy_position_x =  xmlData.my_stage.(@id == iStage_num).my_level.(@id == iLevel_num).enemy[i].@position_x;
				iEnemy_position_y =  xmlData.my_stage.(@id == iStage_num).my_level.(@id == iLevel_num).enemy[i].@position_y;
				//——————————————————————————————这里写构造函数（敌人）
				var EnemyCMD:CreateEnemyCMD = new CreateEnemyCMD( iEnemy_appear_time, iEnemy_enemy_type, iEnemy_position_x, iEnemy_position_y);
				MyEnemyManager.sprCreateEnemyCMD.addChild(EnemyCMD);	
			}
			iTotalEnemyNum = iEnemy_Length;//设定关卡总共的敌人数量
			GameDataController.getInstance().totalEnemies = iTotalEnemyNum;//更新单例里的敌人总数变量
			
			for(var j:Number = 0;j<iProperty_Length;j++)
			{
				iProperty_appear_time = xmlData.my_stage.(@id == iStage_num).my_level.(@id == iLevel_num).property[j].@time;
				iProperty_type = xmlData.my_stage.(@id == iStage_num).my_level.(@id == iLevel_num).property[j].@property_type;
				
				iProperty_type_String = iProperty_type.toString();
				
				iProperty_type_String_length = iProperty_type_String.length;
				
				//trace(j+":"+iProperty_type_String_length);
				for(var p:Number = 0;p<iProperty_type_String_length;p++)
				{
					arrProperty_num = iProperty_type_String.charCodeAt(p)-49;
					arrProperty.push(arrProperty_num);
				}
			}
			var a:int = xmlData.my_stage.length();
			
			//读取关卡长度  放入 GameData单例模式中  可提供选择关卡时调用
			/* 已经放入单例中 
			for(var k:int = 0;k<xmlData.my_stage.length();k++)
			{
				var temp:int = xmlData.my_stage.(@id == k).my_level.length();
				GameDataController.getInstance().LevelInfoArray.push(temp);
			}*/
			
			//——————————————————————————————这里写构造函数（道具）
			if(arrProperty.length == 0)
				return;
			//只有有道具时才建立道具生成指令
			var BonueCMD:CreateBonusCMD = new CreateBonusCMD( iProperty_appear_time, arrProperty);
			MyBonusManager.sprCreateBonusCMD.addChild(BonueCMD);
		}
		
		private function Update(e:Event):void
		{
			if( iState == STAGE_PAUSE )
				return;
			
			RollScreen();
			
			MyFighter.Update();
			MyEnemyManager.Update();
			MyBonusManager.Update();
			
			UpdateEnemy();
			UpdateBonus();
			
			BonusWrongPositionDetection();
			
			CollisionFighterEnemy();
			//CollisionFighterBonus();	
			//CollisionEnemyEnemy();
			
			GameResultControl();
		}
		
		public function Init():void
		{
			
		}
		
		public function Pause():void
		{
			MyFighter.Pause();
			MyEnemyManager.Pause();
			MyBonusManager.Pause();
			iState = STAGE_PAUSE;
		}
		
		public function Continue():void
		{
			MyFighter.Continue();
			MyEnemyManager.Continue();
			MyBonusManager.Continue();
			iState = STAGE_RUNNING;
		}
		
		public function Clear():void
		{
			if(MyFighter!=null)
			{
				MyFighter.Clear();
				MyFighter = null;
			}
			MyEnemy = null;
			MyEnemy2 = null;
			MyEnemy3 = null;
			
			if(MyEnemyManager != null)
			{
				MyEnemyManager.Clear();
				MyEnemyManager = null;
			}
			
			MyBonus = null;
			if(MyBonusManager!=null)
			{
				MyBonusManager.Clear();
				MyBonusManager = null;
			}
			this.removeEventListener(Event.ENTER_FRAME, Update);
			
			if( iStage_num_Rec == 1 )
				CreateSoundEvent( CustomEventSound.STOP_SOUND, SoundInfo.BGM_STAGE_RUNNING_S1, true);
			else if( iStage_num_Rec == 2 )
				CreateSoundEvent( CustomEventSound.STOP_SOUND, SoundInfo.BGM_STAGE_RUNNING_S2, true);
			else if( iStage_num_Rec == 3 )
				CreateSoundEvent( CustomEventSound.STOP_SOUND, SoundInfo.BGM_STAGE_RUNNING_S3, true);
		}
		
	}
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
}